// TxtToSeq.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

using namespace std;

twist_t twists[] =
{
	{ ("{0}") },
	{ ("{1}") },
	{ ("{2}") },
	{ ("{STOP}") },
	{ ("{4}") },
	{ ("{WHITE}") },
	{ ("{6}") },
	{ ("{7}") },
	{ ("{DCS}") },
	{ ("{ECS}") },
	{ ("{10}") },
	{ ("{11}") },
	{ ("{12}") },
	{ ("\n") },
	{ ("{LCS}") },
	{ ("{15}") },

	{ ("{16}") },
	{ ("{DOWN}") },
	{ ("{RVON}") },
	{ ("{HOME}") },
	{ ("{DELETE}") },
	{ ("{21}") },
	{ ("{22}") },
	{ ("{23}") },
	{ ("{24}") },
	{ ("{25}") },
	{ ("{26}") },
	{ ("{27} ") },
	{ ("{RED}") },
	{ ("{RIGHT}") },
	{ ("{GREEN}") },
	{ ("{BLUE}") },

	{ (" ") },
	{ ("!") },
	{ ("{QUOTE}") },
	{ ("#") },
	{ ("$") },
	{ ("%") },
	{ ("&") },
	{ ("'") },
	{ ("(") },
	{ (")") },
	{ ("*") },
	{ ("+") },
	{ (",") },
	{ ("-") },
	{ (".") },
	{ ("/") },

	{ ("0") },
	{ ("1") },
	{ ("2") },
	{ ("3") },
	{ ("4") },
	{ ("5") },
	{ ("6") },
	{ ("7") },
	{ ("8") },
	{ ("9") },
	{ (":") },
	{ (";") },
	{ ("<") },
	{ ("=") },
	{ (">") },
	{ ("?") },

	{ ("@") },
	{ ("a") },
	{ ("b") },
	{ ("c") },
	{ ("d") },
	{ ("e") },
	{ ("f") },
	{ ("g") },
	{ ("h") },
	{ ("i") },
	{ ("j") },
	{ ("k") },
	{ ("l") },
	{ ("m") },
	{ ("n") },
	{ ("o") },

	{ ("p") },
	{ ("q") },
	{ ("r") },
	{ ("s") },
	{ ("t") },
	{ ("u") },
	{ ("v") },
	{ ("w") },
	{ ("x") },
	{ ("y") },
	{ ("z") },
	{ ("[") },
	{ ("{POUND}") },
	{ ("]") },
	{ ("{UPARROW}") },
	{ ("{LEFTARROW}") },

	{ ("{96}") },
	{ ("A") },
	{ ("B") },
	{ ("C") },
	{ ("D") },
	{ ("E") },
	{ ("F") },
	{ ("G") },
	{ ("H") },
	{ ("I") },
	{ ("J") },
	{ ("K") },
	{ ("L") },
	{ ("M") },
	{ ("N") },
	{ ("O") },

	{ ("P") },
	{ ("Q") },
	{ ("R") },
	{ ("S") },
	{ ("T") },
	{ ("U") },
	{ ("V") },
	{ ("W") },
	{ ("X") },
	{ ("Y") },
	{ ("Z") },
	{ ("{CROSS}") },
	{ ("{124}") },
	{ ("{VLINE}") },
	{ ("{126}") },
	{ ("{127}") },

	{ ("{128}") },
	{ ("{ORANGE}") },
	{ ("{130}") },
	{ ("{RUN}") },
	{ ("{132}") },
	{ ("{F1}") },
	{ ("{F3}") },
	{ ("{F5}") },
	{ ("{F7}") },
	{ ("{F2}") },
	{ ("{F4}") },
	{ ("{F6}") },
	{ ("{F8}") },
	{ ("{SRETURN}") },
	{ ("{UCS}") },
	{ ("{143}") },

	{ ("{BLACK}") },
	{ ("{UP}") },
	{ ("{RVOFF}") },
	{ ("{CLEAR}") },
	{ ("{INSERT}") },
	{ ("{BROWN}") },
	{ ("{PINK}") },
	{ ("{DGRAY}") },
	{ ("{MGRAY}") },
	{ ("{LGREEN}") },
	{ ("{LBLUE}") },
	{ ("{LGRAY} ") },
	{ ("{PURPLE}") },
	{ ("{LEFT}") },
	{ ("{YELLOW}") },
	{ ("{CYAN}") },

	{ ("{160}") },
	{ ("{161}") },
	{ ("{162}") },
	{ ("{163}") },
	{ ("{164}") },
	{ ("{165}") },
	{ ("{166}") },
	{ ("{167}") },
	{ ("{168}") },
	{ ("{169}") },
	{ ("{170}") },
	{ ("{LTEE}") },
	{ ("{172}") },
	{ ("{LLCORNER}") },
	{ ("{URCORNER}") },
	{ ("{175}") },

	{ ("{ULCORNER}") },
	{ ("{BTEE}") },
	{ ("{UTEE}") },
	{ ("{RTEE}") },
	{ ("{180}") },
	{ ("{181}") },
	{ ("{182}") },
	{ ("{183}") },
	{ ("{184}") },
	{ ("{185}") },
	{ ("{CHECK}") },
	{ ("{187}") },
	{ ("{188}") },
	{ ("{189}") },
	{ ("{190}") },
	{ ("{191}") },

	{ ("{HLINE}") },
	{ ("{193}") },
	{ ("{194}") },
	{ ("{195}") },
	{ ("{196}") },
	{ ("{197}") },
	{ ("{198}") },
	{ ("{199}") },
	{ ("{200}") },
	{ ("{201}") },
	{ ("{202}") },
	{ ("{203}") },
	{ ("{204}") },
	{ ("{205}") },
	{ ("{206}") },
	{ ("{207}") },

	{ ("{208}") },
	{ ("{209}") },
	{ ("{210}") },
	{ ("{211}") },
	{ ("{212}") },
	{ ("{213}") },
	{ ("{214}") },
	{ ("{215}") },
	{ ("{216}") },
	{ ("{217}") },
	{ ("{218}") },
	{ ("{219}") },
	{ ("{220}") },
	{ ("{221}") },
	{ ("{222}") },
	{ ("{223}") },

	{ ("{224}") },
	{ ("{225}") },
	{ ("{226}") },
	{ ("{227}") },
	{ ("{228}") },
	{ ("{229}") },
	{ ("{230}") },
	{ ("{231}") },
	{ ("{232}") },
	{ ("{233}") },
	{ ("{234}") },
	{ ("{235}") },
	{ ("{236}") },
	{ ("{237}") },
	{ ("{238}") },
	{ ("{239}") },

	{ ("{240}") },
	{ ("{241}") },
	{ ("{242}") },
	{ ("{243}") },
	{ ("{244}") },
	{ ("{245}") },
	{ ("{246}") },
	{ ("{247}") },
	{ ("{248}") },
	{ ("{249}") },
	{ ("{250}") },
	{ ("{251}") },
	{ ("{252}") },
	{ ("{253}") },
	{ ("{254}") },
	{ ("{255}") }

};

void printHelp(void);
char* getCode(unsigned char petscii);
unsigned char getPetscii(char *code);

// define the ID values to indentify the option
enum { OPT_HELP, OPT_INPUT, OPT_OUTPUT, OPT_DIRECTION };

// declare a table of CSimpleOpt::SOption structures. See the SimpleOpt.h header
// for details of each entry in this structure. In summary they are:
//  1. ID for this option. This will be returned from OptionId() during processing.
//     It may be anything >= 0 and may contain duplicates.
//  2. Option as it should be written on the command line
//  3. Type of the option. See the header file for details of all possible types.
//     The SO_REQ_SEP type means an argument is required and must be supplied
//     separately, e.g. "-f FILE"
//  4. The last entry must be SO_END_OF_OPTIONS.
//
CSimpleOpt::SOption g_rgOptions[] = {
	{ OPT_DIRECTION,  _T("-d"),     SO_REQ_CMB }, // "-d=seq"
    { OPT_INPUT,  _T("-i"),     SO_REQ_CMB }, // "-i=file.txt"
    { OPT_OUTPUT,  _T("-o"),     SO_REQ_CMB }, // "-o=file.seq"
    { OPT_HELP, _T("-?"),     SO_NONE    }, // "-?"
    { OPT_HELP, _T("--help"), SO_NONE    }, // "--help"
    SO_END_OF_OPTIONS                       // END
};

int _tmain(int argc, TCHAR* argv[])
{
	wchar_t inputFile[257];
	wchar_t outputFile[257];
	wchar_t direction = 0;
	errno_t r;

	memset(inputFile, 0, sizeof(wchar_t[257]));
	memset(outputFile, 0, sizeof(wchar_t[257]));

    // declare our options parser, pass in the arguments from main
    // as well as our array of valid options.
    CSimpleOpt args(argc, argv, g_rgOptions);

    // while there are arguments left to process
    while (args.Next()) {
        if (args.LastError() == SO_SUCCESS) {
            if (args.OptionId() == OPT_HELP) {
                printHelp();
                return 0;
            }

			switch(args.OptionId())
			{
			case OPT_DIRECTION: 
				if(_tcscmp(args.OptionArg(), _T("seq")) == 0)
				{
					direction = 's';
				}
				else if(_tcscmp(args.OptionArg(), _T("txt")) == 0)
				{
					direction = 't';
				}
				else
				{
					_tprintf(_T("Invalid direction. %s"), args.OptionArg());
					printHelp();
					return 1;
				}
				break;

			case OPT_INPUT:
				if(_tclen(args.OptionArg()) > 0)
				{
					_tcscpy(inputFile, args.OptionArg());
				}
				else
				{
					_tprintf(_T("Invalid input filename."));
					printHelp();
					return 1;
				}
				break;

			case OPT_OUTPUT:
				if(_tclen(args.OptionArg()) > 0)
				{
					_tcscpy(outputFile, args.OptionArg());
				}
				else
				{
					_tprintf(_T("Invalid output filename."));
					printHelp();
					return 1;
				}
				break;
			}
        }
        else {
            _tprintf(_T("Invalid argument: %s\n"), args.OptionText());
            return 1;
        }
    }

	if(_tclen(inputFile) == 0 || _tclen(outputFile) == 0 || direction == 0)
	{
	    printHelp();
        return 0;
	}

	_tprintf(_T("Processing %s to %s as %s\n\n"), inputFile, outputFile, (direction == 's' ? _T("SEQ") : _T("TXT")));

	FILE *infile;
	FILE *outfile;

	if((r = _wfopen_s(&infile, inputFile, _T("rb"))) == 0)
	{
		if((r = _wfopen_s(&outfile, outputFile, _T("wb"))) == 0)
		{
			if(direction == 't')
			{
				unsigned char c;
				while((c = fgetc(infile)) < 255)
				{
					char *code = getCode(c);
					fwrite(code, strlen(code), 1, outfile);
				}

				fclose(outfile);
				fclose(infile);
			}
			else
			{
				unsigned char c = 0;
				char buffer[20];
				bool inTag = false;

				while((c = fgetc(infile)) < 255)
				{
					if(c == _T('{'))
					{
						inTag = true;
						memset(buffer, 0, sizeof(buffer));
						buffer[0] = c;
					}					
					else if(c == _T('}'))
					{
						inTag = false;
						buffer[strlen(buffer)] = c;
						fputc(getPetscii(buffer), outfile);
					}
					else if(inTag)
					{
						buffer[strlen(buffer)] = c;
					}
					else if(c == 10)
					{
						// Do nothing, strip it.
					}
					else
					{
						if(c == 13)
						{
							sprintf_s(buffer, "\n");
						}
						else
						{
							sprintf_s(buffer, "%c", c);
						}
						fputc(getPetscii(buffer), outfile);
					}
				}

				fclose(outfile);
				fclose(infile);
			}
		}
		else
		{
			_tprintf(_T("Could not open %s for writing. [%u]"), outputFile, r);
		}
	}
	else
	{
		_tprintf(_T("Could not open %s for reading. [%u]"), inputFile, r);
	}

	return 0;
}

void printHelp(void)
{
	_tprintf(_T("Usage: TxtToSeq -i=infile -o=outfile -d=(seq|txt)\n"));
}

char* getCode(unsigned char petscii)
{
	if(petscii < 256)
	{
		return twists[petscii].token;
	}

	return ("");
}

unsigned char getPetscii(char *code)
{
	for(unsigned char i=0; i<256; ++i)
	{
		if(strcmp(code, twists[i].token) == 0)
		{
			return i;
		}
	}

	return 0;
}